home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Apple Macintosh Developer Technical Support
- **
- ** Program: DTS.Lib
- ** File: TreeObj.c
- ** Written by: Eric Soldan
- **
- ** Copyright © 1992 Apple Computer, Inc.
- ** All rights reserved.
- */
-
-
-
- #include "DTS.Lib2.h"
- #include "DTS.Lib.protos.h"
-
- #ifndef __FILES__
- #include <Files.h>
- #endif
-
- #ifndef __STDIO__
- #include <StdIO.h>
- #endif
-
- #ifndef __STRING__
- #include <String.h>
- #endif
-
- #ifndef __TREEOBJ__
- #include "TreeObj.h"
- #endif
-
- #ifndef __UTILITIES__
- #include "Utilities.h"
- #endif
-
-
-
- #define NEW_CHILD 1
- #define DISPOSE_CHILD 2
- #define MOVE_CHILD 3
- #define SWAP_CHILDREN 4
- #define CHANGE_CHILD 5
-
-
-
- extern TreeObjProcPtr gTreeObjMethods[];
- extern long gMinTreeObjSize[];
-
- static TreeObjHndl CopyOneChild(TreeObjHndl chndl, TreeObjHndl copyToHndl, short copyCNum);
- static OSErr ReadBranch(TreeObjHndl hndl, short fileRefNum);
- static OSErr ReadTreeObjHeader(TreeObjHndl hndl, short fileRefNum);
- static OSErr WriteTreeObjHeader(TreeObjHndl hndl, short fileRefNum);
-
- static TreeObjHndl GetUndoTaskHndl(TreeObjHndl undo, short editType);
- static TreeObjHndl NewUndoPart(TreeObjHndl taskHndl, short action, TreeObjHndl shndl, short cnum, TreeObjHndl dhndl, short dcnum, Boolean deepCopy);
-
- static OSErr PostNewChild(short editType, TreeObjHndl phndl, short cnum);
- static OSErr PostDisposeChild(short editType, TreeObjHndl phndl, short cnum);
- static void PostMoveChild(short editType, TreeObjHndl shndl, short scnum, TreeObjHndl dhndl, short dcnum);
- static void PostSwapChildren(short editType, TreeObjHndl hndla, short cnuma, TreeObjHndl hndlb, short cnumb);
-
- static void UndoNewChild(TreeObjHndl undoPart);
- static void UndoDisposeChild(TreeObjHndl undoPart);
- static void UndoMoveChild(TreeObjHndl undoPart);
- static void UndoModifyChild(TreeObjHndl undoPart);
- static void UndoModifyChildren(TreeObjHndl dhndl, TreeObjHndl uhndl, Boolean deepCopy);
- static void UndoSwapChildren(TreeObjHndl undoPart);
-
-
-
- /**********************************************************************/
-
-
-
- /* Creates an object with no parent. This object will be the root object
- ** for a tree. Returns nil upon failure. */
-
- #pragma segment File
- TreeObjHndl NewRootObj(short ctype, long size)
- {
- TreeObjHndl root;
- TreeObjPtr ptr;
- char *cptr;
- short i;
- TreeObjProcPtr proc;
-
- if (size < gMinTreeObjSize[ctype])
- size = gMinTreeObjSize[ctype];
- /* Ensure a minimally-sized object. */
-
- root = (TreeObjHndl)NewHandle(sizeof(TreeObj) + size);
- if (!root) return(nil);
- /* Oh well...
- ** Note that since we are creating an orphan, it isn't possible to purge
- ** old undos to possibly make space. This means that for anyone calling
- ** NewRootObj to get a handlewho considers it okay to purge old undos to
- ** get the memory if necessary, has to do the following:
- ** 1) Call NewRootObj
- ** 2) If failure, call PurgeUndo for a particular document to purge the
- ** oldest undo for that document to free up ram.
- ** 3) If PurgeUndo returns true, then something was purged and there is more
- ** ram available. Loop back to step 1 and try to create the object again.
- ** 4) If PurgeUndo returns false, then there really isn't any more ram. One
- ** possibility is to try purging undos from other documents, but this is
- ** probably rude. */
-
- cptr = GetDataPtr(root);
- for (i = 0; i < size; ++i) cptr[i] = 0;
- /* Initialize data area to 0's. This is very nice of us. */
-
- ptr = *root; /* Deref root object once. */
- ptr->type = ctype; /* Flag what object type it is. */
- ptr->numChildren = 0; /* Give root 0 children. */
- ptr->dataSize = size; /* Remember the data area size. */
- ptr->treeID = 0; /* Requisite do-nothing field. */
- ptr->parent = nil; /* We aren't owned yet. */
-
- if (proc = gTreeObjMethods[ctype]) { /* If this object type has a proc... */
- if ((*proc)(root, INITMESSAGE, CREATEINIT)) { /* Call the proc with an init message. */
- DisposeHandle((Handle)root); /* If the init complains, it's no go. */
- return(nil);
- }
- }
-
- return(root); /* Success. Return the handle. */
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Creates a child of the specified type and adds it to the parent at the
- ** specified location. Returns nil upon failure. */
-
- #pragma segment File
- TreeObjHndl NewChild(short editType, TreeObjHndl phndl, short cnum, short ctype, long size)
- {
- TreeObjHndl chndl;
- TreeObjProcPtr proc;
-
- for (;;) {
- chndl = NewRootObj(ctype, size); /* Let somebody else do the creative work. */
- if (chndl) break; /* We succeeded at creating an orphan. */
- if (!PurgeUndo(phndl)) return(nil);
- /* Oh well...
- ** There is really no memory. We even purged the undos to try to make
- ** room, but we still didn't have enough ram to create the orphan object. */
- };
-
- /* Now that we have successfully created an orphan object, make it someone's child. */
-
- GetChildHndlPtr(phndl, &cnum, 1);
- /* Adjust cnum to within bounds. See GetChildHndlPtr() for more info. */
-
- if (InsertChildHndl(phndl, chndl, cnum)) {
- /* Couldn't insert the child into the parent handle table. */
- if (proc = gTreeObjMethods[ctype])
- (*proc)(chndl, FREEMESSAGE, 0);
- /* Since we couldn't attatch, call the object with a free message so that
- ** it can get rid of any additional memory that was allocated when an
- ** init message was sent to it. */
- DisposeHandle((Handle)chndl);
- /* After the free message, the object now consists of a single handle.
- ** Dispose this handle and it is history completely. */
- return(nil);
- }
-
- if (PostNewChild(editType, phndl, cnum)) {
- DisposeChild(NO_EDIT, phndl, cnum);
- chndl = nil;
- }
-
- DoTreeObjMethod(chndl, UNDOMESSAGE, UNDOTODOC);
- return(chndl);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Disposes of the specified child and all offspring of that child. */
-
- #pragma segment File
- void DisposeChild(short editType, TreeObjHndl phndl, short cnum)
- {
- TreeObjHndl chndl;
-
- if (GetChildHndlPtr(phndl, &cnum, 0)) {
- /* This test checks that there are children in the table, plus it
- ** also adjusts cnum to legit values, if possible. */
-
- chndl = GetChildHndl(phndl, cnum);
- DoTreeObjMethod(chndl, UNDOMESSAGE, UNDOFROMDOC);
-
- if (editType) {
- if (PostDisposeChild(editType, phndl, cnum)) {
- /* Posting a DisposeChild can actually take more ram.
- ** The reason for this is that the object isn't disposed of.
- ** It is moved into the undo, plus information as to where to
- ** put it back is kept. If PostDisposeChild fails, then we
- ** are in a bad way memory-wise, so we really need to let the
- ** dispose occur. To accomplish this, we disable undos for
- ** this document, and then we go ahead and allow a straight
- ** dispose of the child. This will get the job done, plus it
- ** will free up some ram.
- ** The reason that undos are disabled is that the edit that
- ** is occuring may have multiple operations. We want to stop
- ** collection of the remaining operations for this edit, as
- ** it wouldn't be a complete undo anyway. The undos will
- ** be enabled again when NewUndo is called to start a new edit. */
- DisableUndo(phndl);
- /* Undo collection off temporarily, plus all undos are purged,
- ** thus freeing up ram. */
- editType = 0;
- }
- }
-
- if (!editType) {
- DisposeObjAndOffspring(GetChildHndl(phndl, cnum));
- *GetChildHndlPtr(phndl, &cnum, 0) = nil;
- /* Since the child no longer exists, DeleteChildHndl can't set
- ** the parent reference for the child to nil. Setting the reference
- ** to the child prevents DeleteChildHndl from doing this. */
- DeleteChildHndl(phndl, cnum);
- }
- }
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Copies the specified child (and all offspring of that child if deepCopy is true). */
-
- #pragma segment File
- TreeObjHndl CopyChild(short editType, TreeObjHndl shndl, short scnum,
- TreeObjHndl dhndl, short dcnum, Boolean deepCopy)
- {
- TreeObjHndl chndl, copyHndl;
-
- if (!GetChildHndlPtr(shndl, &scnum, 0)) return(nil);
- /* Adjust scnum to within bounds, if possible. */
-
- GetChildHndlPtr(dhndl, &dcnum, 1);
- /* Adjust dcnum to within bounds. */
-
- copyHndl = CopyOneChild(chndl = GetChildHndl(shndl, scnum), dhndl, dcnum);
- if (!copyHndl) return(nil);
-
- if (deepCopy) {
- if (CopyChildren(chndl, copyHndl)) { /* Copy child's children. */
- DisposeChild(NO_EDIT, dhndl, dcnum);
- return(nil);
- }
- }
-
- if (PostNewChild(editType, dhndl, dcnum)) {
- DisposeChild(NO_EDIT, dhndl, dcnum);
- return(nil);
- }
-
- DoTreeObjMethod(copyHndl, UNDOMESSAGE, UNDOTODOC);
- return(copyHndl);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Moves a child from one location on the tree to another. */
-
- #pragma segment File
- OSErr MoveChild(short editType, TreeObjHndl shndl, short scnum, TreeObjHndl dhndl, short dcnum)
- {
- TreeObjHndl chndl;
- OSErr err;
-
- if (!GetChildHndlPtr(shndl, &scnum, 0)) return(paramErr);
- /* Adjust scnum to within bounds. Adjustment not possible if no children. */
-
- GetChildHndlPtr(dhndl, &dcnum, 1); /* Adjust dcnum to within bounds. */
-
- chndl = GetChildHndl(shndl, scnum);
-
- if (err = InsertChildHndl(dhndl, chndl, dcnum)) return(err);
- /* See if the child can be moved. If no space at new location, return error. */
-
- DeleteChildHndl(dhndl, dcnum);
- /* The child will be able to be moved, so remove the test addition.
- ** It is important to have the child detached from the tree, as the new
- ** location it is to be moved to is an index based on that the child
- ** isn't attached yet. This only matters if the child is being moved
- ** to a new location for the same parent. */
-
- DeleteChildHndl(shndl, scnum);
- GetChildHndlPtr(dhndl, &dcnum, 1);
- /* Adjust dcnum to within bounds. It may be just out of bounds if shndl
- ** and dhndl are the same. After the DeleteChildHndl, dcnum may be 2 past
- ** the end, instead of the allowable 1 for a target. */
-
- InsertChildHndl(dhndl, chndl, dcnum);
-
- PostMoveChild(editType, shndl, scnum, dhndl, dcnum);
- return(noErr);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Saves a copy of the child in the undo hierarchy for undo/redo purposes. */
-
- #pragma segment File
- OSErr ModifyChild(short editType, TreeObjHndl phndl, short cnum, Boolean deepCopy)
- {
- TreeObjHndl undo, task, part, copy;
- short i;
- OSErr err;
-
- if (!editType) return(noErr);
-
- err = noErr;
- copy = nil;
- undo = GetUndoHndl(phndl);
-
- if (mDerefUndo(undo)->disabled)
- copy = phndl; /* Used for flag purposes. */
-
- else {
- if (task = GetUndoTaskHndl(undo, editType)) {
- for (i = (*task)->numChildren; i;) {
- part = GetChildHndl(task, --i);
- if (mDerefUndoPart(part)->actionType == CHANGE_CHILD)
- if ((mDerefUndoPart(part)->shndl ==phndl) && (mDerefUndoPart(part)->scnum ==cnum))
- return(noErr);
- /* Child is already posted as changed for this undo editType. */
- }
-
- part = NewUndoPart(task, CHANGE_CHILD, phndl, cnum, nil, 0, deepCopy);
- if (part)
- copy = CopyChild(NO_EDIT, phndl, cnum, part, -1, deepCopy);
- }
- }
-
- if (!copy) {
- DisableUndo(phndl);
- err = memFullErr;
- }
-
- return(err);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Swaps the child handles. */
-
- #pragma segment File
- OSErr SwapChildren(short editType, TreeObjHndl hndla, short cnuma, TreeObjHndl hndlb, short cnumb)
- {
- TreeObjHndl *tptra, *tptrb, hndl;
-
- if (!(tptra = GetChildHndlPtr(hndla, &cnuma, 0))) return(paramErr);
- if (!(tptrb = GetChildHndlPtr(hndlb, &cnumb, 0))) return(paramErr);
-
- hndl = *tptra;
- *tptra = *tptrb;
- *tptrb = hndl;
-
- (*GetChildHndl(hndla, cnuma))->parent = hndla;
- (*GetChildHndl(hndlb, cnumb))->parent = hndlb;
-
- PostSwapChildren(editType, hndla, cnuma, hndlb, cnumb);
- return(noErr);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Swaps the child data without swapping the handles. */
-
- #pragma segment File
- OSErr SwapChildData(TreeObjHndl hndla, TreeObjHndl hndlb)
- {
- TreeObjHndl hndl;
- long size, sizea, sizeb, i;
- char *ptra, *ptrb, c;
- OSErr err;
-
- sizea = (*hndla)->dataSize;
- sizeb = (*hndlb)->dataSize;
- if (sizea > sizeb) { /* Make hndla the small one and hndlb the big one. */
- size = sizea;
- sizea = sizeb;
- sizeb = size;
- hndl = hndla;
- hndla = hndlb;
- hndlb = hndl;
- }
-
- err = SetDataSize(hndla, sizeb); /* Make the small one big. */
- if (!err) {
- ptra = GetDataPtr(hndla);
- ptrb = GetDataPtr(hndlb);
- for (i = 0; i < sizeb; ++i) {
- c = ptra[i];
- ptra[i] = ptrb[i];
- ptrb[i] = c;
- }
- SetDataSize(hndlb, sizea); /* Make the big one small. */
- }
-
- return(err);
- }
-
-
-
- /**********************************************************************/
- /**********************************************************************/
-
-
-
- /* This disposes of the child and any offspring of that child. It does not remove
- ** the child from the parent's child handle table. */
-
- #pragma segment File
- void DisposeObjAndOffspring(TreeObjHndl chndl)
- {
- short nc;
- TreeObjProcPtr proc;
-
- if (!chndl) return;
-
- if (proc = gTreeObjMethods[(*chndl)->type])
- (*proc)(chndl, FREEMESSAGE, 0);
- /* If the object has any additional deallocation to do, let it do it. */
-
- while (nc = (*chndl)->numChildren) {
- DisposeObjAndOffspring(GetChildHndl(chndl, nc - 1));
- (*chndl)->numChildren--;
- }
- DisposeHandle((Handle)chndl);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Copies the children (and children below that and so on) of one object to
- ** another object. Used internally by CopyChild for deep copies. */
-
- #pragma segment File
- OSErr CopyChildren(TreeObjHndl shndl, TreeObjHndl dhndl)
- {
- TreeObjHndl chndl, copyHndl;
- short i;
- OSErr err;
-
- for (i = (*shndl)->numChildren; i;) {
- chndl = GetChildHndl(shndl, --i);
- copyHndl = CopyOneChild(chndl, dhndl, 0);
- if (!copyHndl) return(memFullErr);
- if (err = CopyChildren(chndl, copyHndl)) return(err);
- }
- return(noErr);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Used internally by CopyChild for shallow copies. */
-
- #pragma segment File
- TreeObjHndl CopyOneChild(TreeObjHndl chndl, TreeObjHndl copyToHndl, short copycnum)
- {
- TreeObjHndl copyHndl;
- short type;
- long size;
- TreeObjProcPtr proc;
-
- type = (*chndl)->type;
- size = (*chndl)->dataSize;
-
-
- proc = gTreeObjMethods[type]; /* Prevent NewChild() from calling the */
- gTreeObjMethods[type] = nil; /* object for INITMESSAGE. */
-
- copyHndl = NewChild(NO_EDIT, copyToHndl, copycnum, type, size);
- /* NewChild takes care of bounds-checking for copycnum. The child data has
- ** not been fully initialized, as we prevented the INITMESSAGE. */
-
- gTreeObjMethods[type] = proc; /* Re-enable messaging the object. */
-
- if (!copyHndl) return(nil);
-
- BlockMove(GetDataPtr(chndl), GetDataPtr(copyHndl), size);
- if (proc) {
- if ((*proc)(copyHndl, COPYMESSAGE, (long)chndl)) {
- DisposeChild(NO_EDIT, copyHndl, copycnum);
- return(nil);
- }
- }
-
- return(copyHndl);
- }
-
-
-
- /**********************************************************************/
- /**********************************************************************/
-
-
-
- /* Adds an existing child to a parent's child handle table. */
-
- #pragma segment File
- OSErr InsertChildHndl(TreeObjHndl phndl, TreeObjHndl chndl, short cnum)
- {
- TreeObjHndl *tptr;
- TreeObjPtr ptr;
- long oldSize, newSize, dhSize;
- long oldTblSize, tblOffset;
- OSErr err;
-
- oldSize = GetHandleSize((Handle)phndl);
- dhSize = sizeof(TreeObj) + (ptr = *phndl)->dataSize; /* Data + header size. */
-
- oldTblSize = ptr->numChildren * sizeof(TreeObjHndl);
-
- newSize = dhSize + oldTblSize + sizeof(TreeObjHndl);
- newSize |= 0x1F;
- ++newSize;
-
- if (newSize > oldSize) {
- SetHandleSize((Handle)phndl, newSize);
- if (err = MemError()) return(err);
- ptr = *phndl;
- }
-
- tptr = GetChildHndlPtr(phndl, &cnum, 1);
- tblOffset = cnum * sizeof(TreeObjHndl);
- BlockMove((char *)tptr, (char *)(tptr + 1), oldTblSize - tblOffset);
-
- ptr->numChildren++;
- *tptr = chndl;
- (*chndl)->parent = phndl;
- return(noErr);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Removes a child from the parent's child handle table. */
-
- #pragma segment File
- void DeleteChildHndl(TreeObjHndl phndl, short cnum)
- {
- TreeObjHndl *tptr;
- TreeObjHndl chndl;
- TreeObjPtr ptr;
- long dhSize, tblSize, tblOffset;
-
- if (!(tptr = GetChildHndlPtr(phndl, &cnum, 0))) return;
- chndl = *tptr;
-
- dhSize = sizeof(TreeObj) + (ptr = *phndl)->dataSize;
- tblSize = ptr->numChildren * sizeof(TreeObjHndl);
- tblOffset = cnum * sizeof(TreeObjHndl);
-
- BlockMove((char *)(tptr + 1), (char *)tptr, tblSize - tblOffset - sizeof(TreeObjHndl));
- SetHandleSize((Handle)phndl, ((dhSize + tblSize - sizeof(TreeObjHndl)) | 0x1F) + 1);
- (*phndl)->numChildren--;
-
- if (chndl)
- (*chndl)->parent = nil;
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Given an object handle, return the root handle. */
-
- #pragma segment File
- TreeObjHndl GetRootHndl(TreeObjHndl hndl)
- {
- for (; (*hndl)->parent; hndl = (*hndl)->parent);
- return(hndl);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Given a parent handle and a child number, this returns the child handle. */
-
- #pragma segment File
- TreeObjHndl GetChildHndl(TreeObjHndl phndl, short cnum)
- {
- TreeObjHndl *tptr;
-
- if (!(tptr = GetChildHndlPtr(phndl, &cnum, 0))) return(nil);
- return(*tptr);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Return a pointer into the child handle table. This also validates (and corrects)
- ** cnum so that it is in range, if possible. Depending on the usage, pointing to
- ** just after the child handle table is either valid or invalid. If a handle is
- ** being added to the table, then pointing just after the table is valid. If a
- ** handle is being removed or referenced, then pointing just after the table is
- ** invalid. the parameter endCase determines which case we are dealing with. If
- ** endCase is 0, then pointing just after the child handle table is invalid, and
- ** if the cnum value passed in causes this, then nil is returned for the pointer.
- ** if endCase is 1, then pointing just after the child handle table is okay, and
- ** therefore nil will never be returned as the pointer. Any cnum value out of
- ** range will be corrected (if possible) to be within range. */
-
- #pragma segment File
- TreeObjHndl *GetChildHndlPtr(TreeObjHndl phndl, short *cnum, short endCase)
- {
- TreeObjPtr ptr;
- short nc;
- long dhSize, tblOffset;
-
- ptr = *phndl;
- if (!((nc = ptr->numChildren) + endCase)) return(nil);
-
- if ((*cnum < 0) || (*cnum >= nc + endCase))
- *cnum = nc - 1 + endCase;
-
- dhSize = sizeof(TreeObj) + ptr->dataSize;
- tblOffset = *cnum * sizeof(TreeObjHndl);
- return((TreeObjHndl *)((char *)ptr + dhSize + tblOffset));
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Given a child handle, this returns the child number of that
- ** handle in the parent's child handle table. */
-
- #pragma segment File
- short GetChildNum(TreeObjHndl hndl)
- {
- TreeObjHndl phndl, *tptr;
- short nc, j;
-
- if (!(phndl = (*hndl)->parent)) return(-1);
- /* Child doesn't have a parent, and therefore it is a root. */
-
- j = 0;
- if (tptr = GetChildHndlPtr(phndl, &j, 0)) {
- nc = (*phndl)->numChildren;
- for (; j < nc; ++j) if (*tptr++ == hndl) return(j);
- }
-
- return(-1);
- }
-
-
-
- /**********************************************************************/
- /**********************************************************************/
-
-
-
- /* Adjusts the data size, either greater or smaller, depending on the sign of 'delta'. */
-
- #pragma segment File
- OSErr AdjustDataSize(TreeObjHndl hndl, long delta)
- {
- TreeObjPtr ptr;
- long dhSize, tblSize;
- char *cptr;
- OSErr err;
-
- ptr = *hndl;
- tblSize = ptr->numChildren * sizeof (TreeObjHndl);
- dhSize = sizeof(TreeObj) + ptr->dataSize;
-
- if (!(delta & 0x80000000L)) {
- SetHandleSize((Handle)hndl, ((dhSize + tblSize + delta) | 0x1F) + 1);
- if (err = MemError()) return(err);
- ptr = *hndl;
- }
-
- cptr = (char *)ptr + dhSize;
- BlockMove(cptr, cptr + delta, tblSize);
- ptr->dataSize += delta;
-
- if (delta & 0x80000000L)
- SetHandleSize((Handle)hndl, ((dhSize + tblSize + delta) | 0x1F) + 1);
-
- return(noErr);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Sets the data size to newSize. */
-
- #pragma segment File
- OSErr SetDataSize(TreeObjHndl hndl, long newSize)
- {
- return(AdjustDataSize(hndl, newSize - (*hndl)->dataSize));
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Slides some of the data in the data portion of the object starting at
- ** 'offset' by a 'delta' amount, either forward or backward, depending
- ** on the sign of 'delta'. */
-
- #pragma segment File
- OSErr SlideData(TreeObjHndl hndl, long offset, long delta)
- {
- long dhSize;
- char *cptr;
- OSErr err;
-
- if (!(delta & 0x80000000L))
- if (err = AdjustDataSize(hndl, delta)) return(err);
-
- cptr = (char *)GetDataPtr(hndl) + offset;
- dhSize = sizeof(TreeObj) + (*hndl)->dataSize;
- BlockMove(cptr, cptr + delta, dhSize - offset);
-
- if (delta & 0x80000000L)
- AdjustDataSize(hndl, delta);
-
- return(noErr);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Returns a pointer to the beginning of the object's data area.
- ** THIS DOES NOT LOCK THE HANDLE!! The pointer may become invalid
- ** if memory moves. */
-
- #pragma segment File
- void *GetDataPtr(TreeObjHndl hndl)
- {
- return(*(char **)hndl + sizeof(TreeObj));
- }
-
-
-
- /**********************************************************************/
- /**********************************************************************/
-
-
-
- /* Given an open file that has been previously written via WriteTree, this function
- ** is called to read the file data into ram. The root object for the file is already
- ** created by InitDocument. The file must be open, and the file position must be
- ** set to the byte location where the root object of the file starts. Once this is
- ** so, just call this function with a reference to the root object and the open file
- ** refrence number. */
-
- #pragma segment File
- OSErr ReadTree(TreeObjHndl hndl, short fileRefNum)
- {
- OSErr err;
-
- if (err = ReadBranch(hndl, fileRefNum)) {
- DisposeObjAndOffspring(hndl);
- *hndl = nil;
- }
- else {
- DoNumberTree(hndl);
- DoFTreeMethod(hndl, CONVERTMESSAGE, CONVERTTOHNDL);
- }
-
- return(err);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* This is an internal function for recursively reading the data from the
- ** open file. */
-
- #pragma segment File
- OSErr ReadBranch(TreeObjHndl hndl, short fileRefNum)
- {
- TreeObjHndl chndl;
- TreeObjProcPtr proc;
- short numChildren, cnum;
- OSErr err;
-
- if (err = ReadTreeObjHeader(hndl, fileRefNum)) {
- (*hndl)->numChildren = 0; /* So we can dispose the portion that was read. */
- return(err);
- }
-
- numChildren = (*hndl)->numChildren; /* So we can dispose of a partial read if */
- (*hndl)->numChildren = 0; /* we have a failure after this point. */
-
- if (proc = gTreeObjMethods[(*hndl)->type])
- err = (*proc)(hndl, FREADMESSAGE, fileRefNum);
- else
- err = ReadTreeObjData(hndl, fileRefNum);
-
- if (err) return(err);
-
- for (cnum = 0; cnum < numChildren; ++cnum) {
- if (!(chndl = NewRootObj(EMPTYOBJ, 0))) return(memFullErr);
- if (InsertChildHndl(hndl, chndl, cnum)) {
- DisposeObjAndOffspring(chndl);
- return(memFullErr);
- }
- if (err = ReadBranch(chndl, fileRefNum)) return(err);
- }
-
- return(noErr);
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- OSErr ReadTreeObjHeader(TreeObjHndl hndl, short fileRefNum)
- {
- TreeObj header;
- TreeObjHndl parent;
- OSErr err;
- long count;
-
- count = sizeof(TreeObj) - sizeof(TreeObjHndl);
- if (!(err = FSRead(fileRefNum, &count, &header))) {
- parent = (*hndl)->parent;
- **hndl = header;
- (*hndl)->parent = parent;
- }
-
- return(err);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Read in dataSize number of bytes into the object. */
-
- #pragma segment File
- OSErr ReadTreeObjData(TreeObjHndl hndl, short fileRefNum)
- {
- long dataSize;
- OSErr err;
- char hstate;
- Ptr dataPtr;
-
- if (!(err = SetDataSize(hndl, dataSize = (*hndl)->dataSize))) {
- hstate = HGetState((Handle)hndl);
- HLock((Handle)hndl);
- dataPtr = GetDataPtr(hndl);
- err = FSRead(fileRefNum, &dataSize, dataPtr);
- HSetState((Handle)hndl, hstate);
- }
-
- return(err);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Given an open file that is ready to be written to, this function is called to
- ** write the file tree to the designated file. */
-
- #pragma segment File
- OSErr WriteTree(TreeObjHndl hndl, short fileRefNum)
- {
- TreeObjProcPtr proc;
- short cnum;
- OSErr err;
-
- err = WriteTreeObjHeader(hndl, fileRefNum);
- if (!err) {
-
- DoTreeObjMethod(hndl, CONVERTMESSAGE, CONVERTTOID);
- /* Ready data to be written to file. Any references to handles are invalid
- ** when written to disk. These need to be converted to a reference that
- ** makes sense when read in from disk when a file is opened. The standard
- ** way to do this is to convert the handle reference to a tree-obj-number
- ** reference. Prior to WriteTree() being called, DoNumberTree() is called.
- ** DoNumberTree() walks the tree and numbers each handle sequentially, thus
- ** giving each handle a unique id number. */
-
- if (proc = gTreeObjMethods[(*hndl)->type])
- err = (*proc)(hndl, FWRITEMESSAGE, fileRefNum);
- else
- err = WriteTreeObjData(hndl, fileRefNum);
-
- DoTreeObjMethod(hndl, CONVERTMESSAGE, CONVERTTOHNDL);
- /* Undo any id references back to handle references. */
- }
-
-
- if (!err) {
- for (cnum = 0; cnum < (*hndl)->numChildren; ++cnum)
- if (err = WriteTree(GetChildHndl(hndl, cnum), fileRefNum)) break;
- }
-
- return(err);
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- OSErr WriteTreeObjHeader(TreeObjHndl hndl, short fileRefNum)
- {
- TreeObj header;
- OSErr err;
- long count;
-
- header = **hndl;
- count = sizeof(TreeObj) - sizeof(TreeObjHndl);
- err = FSWrite(fileRefNum, &count, &header);
-
- return(err);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Write out dataSize number of bytes from the object. */
-
- #pragma segment File
- OSErr WriteTreeObjData(TreeObjHndl hndl, short fileRefNum)
- {
- long dataSize;
- OSErr err;
- char hstate;
- Ptr dataPtr;
-
- dataSize = (*hndl)->dataSize;
-
- hstate = HGetState((Handle)hndl);
- HLock((Handle)hndl);
- dataPtr = GetDataPtr(hndl);
- err = FSWrite(fileRefNum, &dataSize, dataPtr);
- HSetState((Handle)hndl, hstate);
-
- return(err);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Call the object for each member of the tree (or branch) starting
- ** from the back of the tree working forward. */
-
- #pragma segment File
- void DoBTreeMethod(TreeObjHndl hndl, short message, long data)
- {
- short cnum;
-
- DoTreeObjMethod(hndl, message, data);
-
- for (cnum = (*hndl)->numChildren; cnum;)
- DoBTreeMethod(GetChildHndl(hndl, --cnum), message, data);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Call the object for each member of the tree (or branch) starting
- ** from the front of the tree working backward. */
-
- #pragma segment File
- void DoFTreeMethod(TreeObjHndl hndl, short message, long data)
- {
- short cnum;
-
- DoTreeObjMethod(hndl, message, data);
-
- for (cnum = 0; cnum < (*hndl)->numChildren; ++cnum)
- DoFTreeMethod(GetChildHndl(hndl, cnum), message, data);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* If the object has a method procedure, call it. If no method procedure,
- ** then do nothing. */
-
- #pragma segment File
- long DoTreeObjMethod(TreeObjHndl hndl, short message, long data)
- {
- TreeObjProcPtr proc;
-
- if (proc = gTreeObjMethods[(*hndl)->type]) return((*proc)(hndl, message, data));
- return(0);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Number each member in the tree with a unique treeID. The tree is number
- ** sequentially from front to back. The first treeID number is 1. 0 is
- ** reserved for Hndl2ID/ID2Hndl conversions where it is possible that the
- ** handle value is nil. The nil handle will convert to 0, and convert back
- ** to nil. */
-
- #pragma segment File
- static void DoNumberTree0(TreeObjHndl hndl);
- void DoNumberTree(TreeObjHndl hndl)
- {
- DoNumberTree0(GetRootHndl(hndl));
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- void DoNumberTree0(TreeObjHndl hndl)
- {
- short cnum;
- static short nodeNum;
-
- if (!(*hndl)->parent)
- nodeNum = 0;
- (*hndl)->treeID = ++nodeNum;
-
- for (cnum = 0; cnum < (*hndl)->numChildren; ++cnum)
- DoNumberTree0(GetChildHndl(hndl, cnum));
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* This function is used to convert a handle reference into a treeID reference.
- ** A pointer to the handle reference is passed in. Typical usage will be where
- ** a handle object has a reference to another handle object. Handle object
- ** references aren't meaningful when saved to disk, and therefore don't persist
- ** in their native form. These handle references need to be converted into
- ** a treeID reference so that they can be saved.
- ** The tree first needs to be numbered so that the treeID references are unique
- ** and meaningful. The tree is numbered by first calling DoNumberTree(). It
- ** numbers all the members of the tree hierarchy uniquely and sequentially. */
-
- #pragma segment File
- void Hndl2ID(TreeObjHndl *hndl)
- {
- if (*hndl)
- *hndl = (TreeObjHndl)(**hndl)->treeID;
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Given a tree object ID and a reference object (any member of the tree),
- ** return the cooresponding object handle. DoNumberTree() must be called
- ** prior to using this function, and after the last change to the tree, as
- ** it generates the object treeID numbers for the entire tree. */
-
- #pragma segment File
- void ID2Hndl(TreeObjHndl refHndl, TreeObjHndl *hndl)
- {
- short cnum;
- TreeObjHndl chndl;
-
- if ((!refHndl) || (!*hndl)) return;
-
- refHndl = GetRootHndl(refHndl);
- for (;;) {
- if ((*refHndl)->treeID == (long)*hndl) {
- *hndl = refHndl;
- return;
- }
- if (!(cnum = (*refHndl)->numChildren)) return;
- for (; cnum;) {
- chndl = GetChildHndl(refHndl, --cnum);
- if ((*chndl)->treeID <= (long)*hndl) {
- refHndl = chndl;
- break;
- }
- }
- }
- }
-
-
-
- /**********************************************************************/
- /**********************************************************************/
- /**********************************************************************/
-
-
-
- /* Given an object handle, return the undo handle. */
-
- #pragma segment File
- TreeObjHndl GetUndoHndl(TreeObjHndl undo)
- {
- for (; (*undo)->parent; undo = (*undo)->parent);
- if ((*undo)->type == ROOTOBJ)
- undo = mDerefRoot(undo)->undo;
- return(undo);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Used to close out an old undo task. Closing out the old task means that
- ** any editing to the document will be recorded into a new undo task. Use
- ** this to separate two edits of the same edit type that would otherwise
- ** get recorded into the same undo task. */
-
- #pragma segment File
- void NewUndo(TreeObjHndl hndl)
- {
- TreeObjHndl undo;
-
- undo = GetUndoHndl(hndl);
- mDerefUndo(undo)->lastEditType = NO_EDIT;
- mDerefUndo(undo)->disabled = false;
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* If an edit fails, it can be backed out of by calling this. All edits
- ** that were done will be undone, thus recovering the state of the
- ** document prior to the edit. */
-
- #pragma segment File
- void RevertEdit(TreeObjHndl hndl)
- {
- TreeObjHndl root;
- FileRecHndl frHndl;
- Boolean docDirty;
-
- root = GetRootHndl(hndl);
- frHndl = mDerefRoot(root)->frHndl;
- docDirty = (*frHndl)->fileState.docDirty;
-
- DoUndoTask(hndl, DOUNDO, false);
- /* Use the undo mechanism to back out of the edit task. */
-
- DisposeChild(NO_EDIT, GetUndoHndl(hndl), -1);
- /* Get rid of the undo that was just used to revert.
- ** Leave the rest of the undos. */
-
- (*frHndl)->fileState.docDirty = docDirty;
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Call this to undo or redo editing to the document. If redo is false,
- ** the it is an undo task. */
-
- #pragma segment File
- void DoUndoTask(TreeObjHndl hndl, Boolean redo, Boolean fixup)
- {
- FileRecHndl frHndl;
- TreeObjHndl undo, undoTask, undoPart;
- short numUndos, undoDepth, undoPartNum;
- short beg, end, inc;
- Point contOrg;
-
- NewUndo(undo = GetUndoHndl(hndl));
-
- numUndos = (*undo)->numChildren;
- undoDepth = mDerefUndo(undo)->undoDepth;
-
- if ((redo) && (numUndos == undoDepth)) return;
- if (!(numUndos | undoDepth)) return;
-
- frHndl = mDerefUndo(undo)->frHndl;
-
- if (redo) undoDepth++;
- undoTask = GetChildHndl(undo, --undoDepth);
-
- if (!redo) {
- GetContentOrigin((*frHndl)->fileState.window, &contOrg);
- mDerefUndoTask(undoTask)->redoOrigin = contOrg;
- contOrg = mDerefUndoTask(undoTask)->undoOrigin;
- }
- else contOrg = mDerefUndoTask(undoTask)->redoOrigin;
-
- if (fixup)
- DoUndoFixup(frHndl, contOrg, 0);
- /* Prepare for undo task, such as deselecting the current selection so
- ** that the undone stuff can be displayed as the only selected stuff. */
-
- beg = (*undoTask)->numChildren - 1;
- end = -1;
- inc = -1;
- if (redo) {
- end = ++beg;
- beg = 0;
- inc = 1;
- }
-
- for (undoPartNum = beg; undoPartNum != end; undoPartNum += inc) {
- undoPart = GetChildHndl(undoTask, undoPartNum);
- switch(mDerefUndoPart(undoPart)->actionType) {
- case NEW_CHILD:
- UndoNewChild(undoPart);
- break;
- case DISPOSE_CHILD:
- UndoDisposeChild(undoPart);
- break;
- case MOVE_CHILD:
- UndoMoveChild(undoPart);
- break;
- case CHANGE_CHILD:
- UndoModifyChild(undoPart);
- break;
- case SWAP_CHILDREN:
- UndoSwapChildren(undoPart);
- break;
- }
- }
-
- inc = -1;
- if (redo)
- inc = 1;
-
- mDerefUndo(undo)->undoDepth += inc;
-
- if (fixup)
- DoUndoFixup(frHndl, contOrg, 1);
- /* Clean up and redisplay after undo task. */
-
- SetDocDirty(frHndl);
- }
-
-
-
- /**********************************************************************/
-
-
-
- TreeObjHndl GetUndoTaskHndl(TreeObjHndl undo, short editType)
- {
- TreeObjHndl lastTaskHndl;
- short lastEditType, undoDepth, addNewUndo, numUndoLevels, maxNumUndos;
- Point contOrg;
- FileRecHndl frHndl;
- WindowPtr window;
-
- if (!(maxNumUndos = mDerefUndo(undo)->maxNumUndos)) return(nil);
-
- lastEditType = mDerefUndo(undo)->lastEditType;
- undoDepth = mDerefUndo(undo)->undoDepth;
-
- addNewUndo = false;
- if (editType != lastEditType)
- addNewUndo = true;
- if (!(numUndoLevels = (*undo)->numChildren))
- addNewUndo = true;
-
- while (undoDepth < numUndoLevels) {
- DisposeChild(NO_EDIT, undo, --numUndoLevels);
- addNewUndo = true; /* Flushing old also indicates a new undo. */
- } /* undoDepth now is the same as numUndoLevels. */
-
- lastTaskHndl = nil;
- if (!addNewUndo) {
- lastTaskHndl = GetChildHndl(undo, -1); /* Get last child handle. */
- if ((editType) && (editType != mDerefUndoTask(lastTaskHndl)->editType))
- lastTaskHndl = nil;
- }
-
- if (!lastTaskHndl) {
- while (numUndoLevels >= maxNumUndos) {
- DisposeChild(NO_EDIT, undo, 0);
- mDerefUndo(undo)->undoDepth--;
- numUndoLevels--;
- } /* Restrict number of undos to designated level. */
-
- if (lastTaskHndl = NewChild(NO_EDIT, undo, numUndoLevels, UNDOTASKOBJ, 0)) {
- mDerefUndo(undo)->lastEditType = editType;
- mDerefUndo(undo)->undoDepth++;
- frHndl = mDerefUndo(undo)->frHndl;
- window = (*frHndl)->fileState.window;
- GetContentOrigin(window, &contOrg);
- mDerefUndoTask(lastTaskHndl)->editType = editType;
- mDerefUndoTask(lastTaskHndl)->undoOrigin = contOrg;
- mDerefUndoTask(lastTaskHndl)->redoOrigin = contOrg;
- }
- }
-
- return(lastTaskHndl);
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- TreeObjHndl NewUndoPart(TreeObjHndl taskHndl, short action, TreeObjHndl shndl, short scnum,
- TreeObjHndl dhndl, short dcnum, Boolean deepCopy)
- {
- TreeObjHndl partHndl;
- UndoPartObj *partPtr;
-
- partHndl = NewChild(NO_EDIT, taskHndl, -1, UNDOPARTOBJ, 0); /* Add new child to end. */
- if (partHndl) {
- partPtr = GetDataPtr(partHndl);
- partPtr->actionType = action;
- partPtr->shndl = shndl;
- partPtr->scnum = scnum;
- partPtr->dhndl = dhndl;
- partPtr->dcnum = dcnum;
- partPtr->deepCopy = deepCopy;
- }
-
- return(partHndl);
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- OSErr PostNewChild(short editType, TreeObjHndl phndl, short cnum)
- {
- TreeObjHndl undo, task;
-
- if (!editType) return(noErr);
-
- undo = GetUndoHndl(phndl);
- if (mDerefUndo(undo)->disabled) return(noErr);
-
- if (task = GetUndoTaskHndl(undo, editType))
- if (NewUndoPart(task, NEW_CHILD, phndl, cnum, nil, 0, false)) return(noErr);
-
- return(memFullErr);
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- OSErr PostDisposeChild(short editType, TreeObjHndl phndl, short cnum)
- {
- TreeObjHndl undo, task, part;
-
- if (!editType) return(noErr);
-
- undo = GetUndoHndl(phndl);
- if (mDerefUndo(undo)->disabled) return(noErr);
-
- if (task = GetUndoTaskHndl(undo, editType)) {
- part = NewUndoPart(task, DISPOSE_CHILD, phndl, cnum, nil, 0, false);
- if (part) {
- MoveChild(NO_EDIT, phndl, cnum, part, -1);
- return(noErr);
- }
- }
-
- return(memFullErr);
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- void PostMoveChild(short editType, TreeObjHndl shndl, short scnum, TreeObjHndl dhndl, short dcnum)
- {
- TreeObjHndl undo, task;
-
- if (editType) {
- undo = GetUndoHndl(shndl);
- if (!mDerefUndo(undo)->disabled)
- if (task = GetUndoTaskHndl(undo, editType))
- NewUndoPart(task, MOVE_CHILD, shndl, scnum, dhndl, dcnum, false);
- }
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- void PostSwapChildren(short editType, TreeObjHndl hndla, short cnuma, TreeObjHndl hndlb, short cnumb)
- {
- TreeObjHndl undo, task;
-
- if (editType) {
- undo = GetUndoHndl(hndla);
- if (!mDerefUndo(undo)->disabled)
- if (task = GetUndoTaskHndl(undo, editType))
- NewUndoPart(task, SWAP_CHILDREN, hndla, cnuma, hndlb, cnumb, false);
-
- }
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- void UndoNewChild(TreeObjHndl undoPart)
- {
- TreeObjHndl shndl, chndl;
- short scnum;
-
- shndl = mDerefUndoPart(undoPart)->shndl;
- scnum = mDerefUndoPart(undoPart)->scnum;
- mDerefUndoPart(undoPart)->actionType = DISPOSE_CHILD;
-
- chndl = GetChildHndl(shndl, scnum);
- DoTreeObjMethod(chndl, UNDOMESSAGE, UNDOFROMDOC);
- MoveChild(NO_EDIT, shndl, scnum, undoPart, 0);
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- void UndoDisposeChild(TreeObjHndl undoPart)
- {
- TreeObjHndl shndl, chndl;
- short scnum;
-
- shndl = mDerefUndoPart(undoPart)->shndl;
- scnum = mDerefUndoPart(undoPart)->scnum;
- mDerefUndoPart(undoPart)->actionType = NEW_CHILD;
-
- chndl = GetChildHndl(undoPart, 0);
- MoveChild(NO_EDIT, undoPart, 0, shndl, scnum);
- DoTreeObjMethod(chndl, UNDOMESSAGE, UNDOTODOC);
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- void UndoMoveChild(TreeObjHndl undoPart)
- {
- TreeObjHndl shndl, dhndl;
- short scnum, dcnum;
-
- shndl = mDerefUndoPart(undoPart)->shndl;
- scnum = mDerefUndoPart(undoPart)->scnum;
- dhndl = mDerefUndoPart(undoPart)->dhndl;
- dcnum = mDerefUndoPart(undoPart)->dcnum;
-
- DoTreeObjMethod(GetChildHndl(dhndl, dcnum), UNDOMESSAGE, UNDOFROMDOC);
- MoveChild(NO_EDIT, dhndl, dcnum, shndl, scnum);
- DoTreeObjMethod(GetChildHndl(shndl, scnum), UNDOMESSAGE, UNDOTODOC);
-
- mDerefUndoPart(undoPart)->shndl = dhndl;
- mDerefUndoPart(undoPart)->scnum = dcnum;
- mDerefUndoPart(undoPart)->dhndl = shndl;
- mDerefUndoPart(undoPart)->dcnum = scnum;
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- void UndoModifyChild(TreeObjHndl undoPart)
- {
- TreeObjHndl shndl, dchndl, uchndl;
- short scnum;
-
- shndl = mDerefUndoPart(undoPart)->shndl;
- scnum = mDerefUndoPart(undoPart)->scnum;
-
- dchndl = GetChildHndl(shndl, scnum); /* Document child handle. */
- uchndl = GetChildHndl(undoPart, 0); /* Undo child handle. */
-
- UndoModifyChildren(dchndl, uchndl, mDerefUndoPart(undoPart)->deepCopy);
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- void UndoModifyChildren(TreeObjHndl dhndl, TreeObjHndl uhndl, Boolean deepCopy)
- {
- TreeObjHndl dchndl, uchndl;
- short i;
-
- DoTreeObjMethod(dhndl, UNDOMESSAGE, UNDOFROMDOC); /* Old data leaving document. */
- SwapChildData(dhndl, uhndl);
- DoTreeObjMethod(dhndl, UNDOMESSAGE, UNDOTODOC); /* New data entering document. */
-
- if (deepCopy) {
- for (i = (*dhndl)->numChildren; i;) {
- dchndl = GetChildHndl(dhndl, --i);
- uchndl = GetChildHndl(uhndl, i);
- UndoModifyChildren(dchndl, uchndl, deepCopy);
- }
- }
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- void UndoSwapChildren(TreeObjHndl undoPart)
- {
- TreeObjHndl shndl, dhndl, schndl, dchndl;
- short scnum, dcnum;
-
- shndl = mDerefUndoPart(undoPart)->shndl;
- scnum = mDerefUndoPart(undoPart)->scnum;
- dhndl = mDerefUndoPart(undoPart)->dhndl;
- dcnum = mDerefUndoPart(undoPart)->dcnum;
-
- schndl = GetChildHndl(shndl, scnum);
- dchndl = GetChildHndl(dhndl, dcnum);
-
- DoTreeObjMethod(schndl, UNDOMESSAGE, UNDOFROMDOC);
- DoTreeObjMethod(dchndl, UNDOMESSAGE, UNDOFROMDOC);
-
- SwapChildren(NO_EDIT, shndl, scnum, dhndl, dcnum);
-
- DoTreeObjMethod(schndl, UNDOMESSAGE, UNDOTODOC);
- DoTreeObjMethod(dchndl, UNDOMESSAGE, UNDOTODOC);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Dispose of all undo information and prevent further undo collection.
- ** Calling NewUndo() will re-enable undo collection. */
-
- #pragma segment File
- void DisableUndo(TreeObjHndl hndl)
- {
- TreeObjHndl undo;
-
- undo = GetUndoHndl(hndl);
- while ((*undo)->numChildren) DisposeChild(NO_EDIT, undo, 0);
-
- mDerefUndo(undo)->undoDepth = 0;
- mDerefUndo(undo)->disabled = true;
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Dispose of all undo information and prevent further undo collection.
- ** Calling NewUndo() will re-enable undo collection. */
-
- #pragma segment File
- void DisposeUndos(TreeObjHndl hndl)
- {
- DisableUndo(hndl);
- NewUndo(hndl);
- }
-
-
-
- /**********************************************************************/
-
-
-
- /* Dispose of all undo information except the current undo. The current undo
- ** may still be active, and it may be needed to back out of an edit operation. */
-
- #pragma segment File
- Boolean PurgeUndo(TreeObjHndl hndl)
- {
- TreeObjHndl undo;
- Boolean didPurge;
-
- undo = GetUndoHndl(hndl);
- didPurge = false;
- while ((*undo)->numChildren > 1) {
- DisposeChild(NO_EDIT, undo, 0);
- didPurge = true;
- }
-
- return(didPurge);
- }
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment File
- void GetUndoInfo(FileRecHndl frHndl, short *undoDepth, short *numUndos)
- {
- TreeObjHndl undo;
-
- *undoDepth = *numUndos = 0;
- if ((*frHndl)->fileState.readOnly) return;
-
- undo = GetUndoHndl((*frHndl)->d.doc.root);
- if (!mDerefUndo(undo)->disabled) {
- *undoDepth = mDerefUndo(undo)->undoDepth;
- *numUndos = (*undo)->numChildren;
- }
- }
-
-
-
-